use std::collections::HashSet;

use tracing::debug;

use bc_base::{self, BlockId, block::Block, transaction::Transaction};
use bc_p2p::{ContentResponse, PeerId, ResponseChannel, network_api::P2PEventForApp};

use crate::{BcManager, BcManagerError};

impl BcManager {
    pub async fn broadcast_tx_to_p2p_network(&self, tx: Transaction) -> Result<(), BcManagerError> {
        debug!("Broadcasting transaction to p2p network:\n{:?}", tx);
        let p2p_network = self.p2p_network.lock().await;
        p2p_network.broadcast_tx(&tx).await;

        Ok(())
    }

    pub async fn broadcast_block_to_p2p_network(&self, block: Block) -> Result<(), BcManagerError> {
        debug!("Broadcasting block to p2p network:\n{:?}", block);
        self.p2p_network.lock().await.broadcast_block(&block).await;
        Ok(())
    }

    pub async fn start_providing(&self, block_id: &BlockId) {
        self.p2p_network
            .lock()
            .await
            .start_providing(block_id)
            .await;
    }

    pub async fn get_providers(&self, block_id: &BlockId) -> HashSet<PeerId> {
        self.p2p_network.lock().await.get_providers(block_id).await
    }

    pub async fn request_content(
        &self,
        peer: &PeerId,
        block_id: &BlockId,
    ) -> Result<Block, BcManagerError> {
        let r = self
            .p2p_network
            .lock()
            .await
            .request_content(peer, block_id)
            .await?;
        Ok(r)
    }

    pub async fn respond_content(
        &self,
        content: Result<Block, String>,
        channel: ResponseChannel<ContentResponse>,
    ) {
        self.p2p_network
            .lock()
            .await
            .respond_content(content, channel)
            .await;
    }

    pub async fn register_topic_of_block(&self) {
        self.p2p_network
            .lock()
            .await
            .register_topic_of_block()
            .await;
    }

    pub async fn register_topic_of_tx(&self) {
        self.p2p_network.lock().await.register_topic_of_tx().await;
    }

    pub async fn take_event_receiver_for_app(
        &mut self,
    ) -> tokio::sync::mpsc::Receiver<P2PEventForApp> {
        self.p2p_network.lock().await.take_event_receiver_for_app()
    }

    pub async fn is_block_topic(&self, topic_name: &str) -> bool {
        self.p2p_network.lock().await.is_block_topic(topic_name)
    }

    pub async fn is_tx_topic(&self, topic_name: &str) -> bool {
        self.p2p_network.lock().await.is_tx_topic(topic_name)
    }
}
